package org.dromara.llm.tts.factory;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.llm.domain.LlmConfigType;
import org.dromara.llm.domain.SysLlmConfig;
import org.dromara.llm.service.ISysLlmConfigService;
import org.dromara.llm.tts.TtsService;
import org.dromara.llm.tts.providers.AliyunTtsService;
import org.dromara.llm.tts.providers.EdgeTtsService;
import org.dromara.llm.tts.providers.VolcengineTtsService;
import org.dromara.llm.tts.providers.XfyunTtsService;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 语音合成服务工厂
 */
@RequiredArgsConstructor
@Component
@Slf4j
public class TtsServiceFactory {
    // 语音生成文件保存地址
    @Value("${app.audios:audio/}")
    private static final String outputPath = "audio/";
    // 默认服务提供商名称
    private static final String DEFAULT_PROVIDER = "edge";
    private static final Long DEFAULT_PROVIDER_ID = -1L;
    // 默认 EDGE TTS 服务默认语音名称
    private static final String DEFAULT_VOICE = "zh-CN-XiaoyiNeural";
    // 缓存已初始化的服务：键为"provider:configId:voiceName"格式，确保音色变化时创建新实例
    private final Map<String, TtsService> serviceCache = new ConcurrentHashMap<>();
    // 服务配置服务
    private final ISysLlmConfigService sysLlmConfigService;

    /**
     * 创建缓存键，包含provider、configId和voiceName，确保音色变化时创建新的服务实例
     *
     * @param config    系统配置对象
     * @param provider  服务提供商名称
     * @param voiceName 语音名称
     * @return 缓存键
     */
    // 创建缓存键，包含provider、configId和voiceName，确保音色变化时创建新的服务实例
    private String createCacheKey(SysLlmConfig config, String provider, String voiceName) {
        Long configId = DEFAULT_PROVIDER_ID;
        if (config != null && config.getId() != null) {
            configId = config.getId();
        }
        return provider + ":" + configId + ":" + voiceName;
    }

    /**
     * 获取默认TTS服务
     */
    public TtsService getDefaultTtsService() {
        // 如果数据库中没有默认服务，则创建一个edge，否则使用数据库中默认服务
        SysLlmConfig sysLlmConfig = sysLlmConfigService.queryDefaultLlmConfig(LlmConfigType.TTS);
        if (sysLlmConfig == null) {
            SysLlmConfig config = new SysLlmConfig();
            config.setProvider(DEFAULT_PROVIDER);
            config.setId(DEFAULT_PROVIDER_ID);
            return getTtsService(config, TtsServiceFactory.DEFAULT_VOICE);
        } else {
            // 创建新的服务实例
            try {
                // 当ConfigType=TTS时 发音人用configName字段，因此直接使用configName作为voiceName
                var cacheKey = createCacheKey(sysLlmConfig, sysLlmConfig.getProvider(), sysLlmConfig.getConfigName());
                var service = createApiService(sysLlmConfig);
                serviceCache.put(cacheKey, service);
                return service;
            } catch (Exception e) {
                log.error("创建{}服务失败", sysLlmConfig.getProvider(), e);
                return getDefaultTtsService(); // 失败时返回默认服务
            }
        }


    }

    /**
     * 根据配置获取TTS服务
     */
    public TtsService getTtsService(SysLlmConfig config, String voiceName) {
        String provider;
        // 如果提供商为空，则使用默认提供商
        if (ObjectUtils.isEmpty(config)) {
            provider = DEFAULT_PROVIDER;
        } else {
            provider = config.getProvider();
        }
        var cacheKey = createCacheKey(config, provider, voiceName);
        // 检查是否已有该配置的服务实例
        if (serviceCache.containsKey(cacheKey)) {
            return serviceCache.get(cacheKey);
        }
        // 如果是默认提供商且尚未初始化，则初始化
        if (DEFAULT_PROVIDER.equals(provider)) {
            var service = new EdgeTtsService(StringUtils.hasText(voiceName) ? voiceName : DEFAULT_VOICE, outputPath);
            serviceCache.put(cacheKey, service);
        }
        // 创建新的服务实例
        try {
            var service = createApiService(config);
            serviceCache.put(cacheKey, service);
            return service;
        } catch (Exception e) {
            log.error("创建{}服务失败", provider, e);
            return getDefaultTtsService(); // 失败时返回默认服务
        }
    }

    /**
     * 根据系统配置和指定的声音名称创建TTS服务实例
     *
     * @param config 系统配置对象，包含TTS服务提供商等信息
     * @return 返回对应提供商的TTS服务实例，如果提供商不支持则返回null
     */
    private TtsService createApiService(SysLlmConfig config) {
        // Make sure output dir exists
        ensureOutputPath();
        String voiceName = StringUtils.hasText(config.getConfigName()) ? config.getConfigName() : DEFAULT_VOICE;
        // 获取系统配置中的TTS服务提供商
        return switch (config.getProvider()) {
            case "aliyun" -> new AliyunTtsService(config, voiceName, outputPath);
            case "volcengine" -> new VolcengineTtsService(config, voiceName, outputPath);
            case "xfyun" -> new XfyunTtsService(config, voiceName, outputPath);
            default -> new EdgeTtsService(voiceName, outputPath);
        };
    }

    /**
     * 确保输出目录存在
     */
    private void ensureOutputPath() {
        File dir = new File(TtsServiceFactory.outputPath);
        if (!dir.exists()) dir.mkdirs();
    }

    /**
     * 移除缓存中的指定配置的服务实例
     * TODO 什么时候移除缓存？
     */
    public void removeCache(SysLlmConfig config) {
        if (config == null) {
            return;
        }
        String provider = config.getProvider();
        Long configId = config.getId();
        // 遍历缓存的所有键，找到匹配的键并移除
        serviceCache.keySet().removeIf(key -> {
            String[] parts = key.split(":");
            if (parts.length != 3) {
                return false;
            }
            String keyProvider = parts[0];
            String keyConfigId = parts[1];
            // 检查provider和configId是否匹配
            return keyProvider.equals(provider) && keyConfigId.equals(String.valueOf(configId));
        });
    }

}
